package com.xr.core.system.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.xr.core.system.common.base.MyServiceImpl;
import com.xr.core.system.common.constants.Constant;
import com.xr.core.system.common.constants.Regular;
import com.xr.core.system.common.enums.ResultEnum;
import com.xr.core.system.common.exception.ServiceException;
import com.xr.core.system.common.utils.CurrentLoginUserUtil;
import com.xr.core.system.entity.userModule.AdminMenuVO;
import com.xr.core.system.entity.userModule.AssociatedRoleDTO;
import com.xr.core.system.entity.userModule.PasswordDTO;
import com.xr.core.system.entity.userModule.User;
import com.xr.core.system.mapper.UserMapper;
import com.xr.core.system.service.RoleService;
import com.xr.core.system.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 总后台用户表(User)表服务实现类
 */
@Service("userService")
public class UserServiceImpl extends MyServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private RoleService roleService;

    /**
     * 修改当前登录人密码
     *
     * @param passwordDTO
     * @return
     */
    @Override
    public boolean setPassword(PasswordDTO passwordDTO) {
        Long userId = CurrentLoginUserUtil.getUserId();
        User user = baseMapper.selectById(userId);
        if (!StrUtil.equals(DigestUtil.bcrypt(passwordDTO.getOldPassword()), user.getPassword())) {
            throw new ServiceException("旧密码不正确！");
        } else {
            user.setPassword((DigestUtil.bcrypt(passwordDTO.getNewPassword())));
            return SqlHelper.retBool(baseMapper.updateById(user));
        }
    }

    /**
     * 用户指定角色
     *
     * @param associatedRoleDTO
     * @return
     */
    @Override
    public boolean associatedRole(AssociatedRoleDTO associatedRoleDTO) {
        baseMapper.removeAssociatedRole(associatedRoleDTO);
        boolean res = SqlHelper.retBool(baseMapper.associatedRole(associatedRoleDTO));
        if (res) {
            // 删除该用户登录的角色权限
            SaSession session = StpUtil.getSessionByLoginId(associatedRoleDTO.getAccId(), false);
            if (null != session) {
                session.delete("Role_List");
            }
        }
        return res;
    }

    /**
     * 启禁用账户
     *
     * @param accountId 账户id
     */
    @Override
    public boolean disOrEnaAccount(Long accountId) {
        User user = new User();
        LambdaUpdateWrapper<User> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(User::getInitial, false).setSql("enable = not enable").eq(User::getId, accountId);
        return SqlHelper.retBool(baseMapper.update(user, updateWrapper));
    }

    /**
     * 获取当前登录人菜单
     */
    @Override
    public List<AdminMenuVO> getMenuList() {
        List<AdminMenuVO> menuList = baseMapper.getMenuListByUserId(CurrentLoginUserUtil.getUserId());
        if (menuList.size() == 0) {
            return Collections.emptyList();
        }
        Map<Long, List<AdminMenuVO>> collect = menuList.stream().collect(Collectors.groupingBy(AdminMenuVO::getParentId));
        List<AdminMenuVO> parent = collect.get(0L);
        parseList(parent, collect);
        return parent;
    }

    /**
     * 递归拼接菜单
     */
    private void parseList(List<AdminMenuVO> parent, Map<Long, List<AdminMenuVO>> permissions) {
        for (AdminMenuVO adminMenuVO : parent) {
            Long id = adminMenuVO.getPermissionId();
            List<AdminMenuVO> children = permissions.get(id);
            if (CollectionUtil.isNotEmpty(children)) {
                adminMenuVO.setSubMenu(children);
                parseList(children, permissions);
            }
        }
    }

    /**
     * 新增数据
     *
     * @param user
     * @return
     */
    @Override
    public boolean insert(User user) {
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(User::getAccount, user.getAccount());
        User exist = baseMapper.selectOne(queryWrapper);
        if (exist != null) {
            throw new ServiceException("当前用户名已存在！");
        }
        user.setPassword(DigestUtil.bcrypt(user.getPassword()));
        user.setEnable(true);
        user.setInitial(false);
        int insert = baseMapper.insert(user);
        // 添加默认角色
        List<Object> roleIds = roleService.listDefaultRole();
        if (roleIds != null && roleIds.size() > 0) {
            baseMapper.associatedRole(new AssociatedRoleDTO(user.getId(), roleIds));
        }
        return SqlHelper.retBool(insert);
    }

    /**
     * 修改数据
     *
     * @param user
     * @return
     */
    @Override
    public boolean update(User user) {
        // 禁止修改账户名
        user.setAccount(null);
        String password = user.getPassword();
        if (StrUtil.isNotBlank(password)) {
            boolean match = ReUtil.isMatch(Regular.PASSWORD, password);
            if (!match) {
                throw new ServiceException(Regular.PASSWORD_MASSAGE, ResultEnum.PARAMETER_ERROR);
            }
            user.setPassword(DigestUtil.bcrypt(password));
        }
        return SqlHelper.retBool(baseMapper.updateById(user));
    }

    /**
     * 批量设置内置账户
     *
     * @param idList 账户id
     */
    @Override
    public boolean setInitAccount(List<Long> idList) {
        if (idList.size() > 0) {
            // 去除所有内置账户
            LambdaUpdateWrapper<User> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.eq(User::getInitial, true).set(User::getInitial, false);
            User entity = new User();
            baseMapper.update(entity, updateWrapper);
            // 重新分配内置账户
            LambdaUpdateWrapper<User> updateInitWrapper = Wrappers.lambdaUpdate();
            updateInitWrapper.in(User::getId, idList).set(User::getInitial, true);
            return SqlHelper.retBool(baseMapper.update(entity, updateInitWrapper));
        }
        return false;
    }

    /**
     * 获取验证码
     *
     * @param response
     */
    @Override
    public void getVerification(HttpServletResponse response) {
        // 定义图形验证码的长、宽、验证码字符数、干扰元素个数
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(100, 32, 4, 4);
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            Cookie cookie = new Cookie("verificationCode", captcha.getCode());
            cookie.setPath("/");
            cookie.setMaxAge(1800);
            response.addCookie(cookie);
            SaSession tokenSession = StpUtil.getTokenSession();
            tokenSession.delete(Constant.CAPTCHA_SESSION_KEY);
            tokenSession.set(Constant.CAPTCHA_SESSION_KEY, captcha.getCode());
            // 图形验证码写出，可以写出到文件，也可以写出到流
            captcha.write(outputStream);
            outputStream.flush();
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 通过userId 获取权限code
     *
     * @param id 用户id
     * @return 权限code
     */
    @Override
    public List<String> roleCodeByUserId(Long id) {
        return baseMapper.selectRoleCodeByUserId(id);
    }

}

